/** 
 * Copyright 2010 Daniel Guermeur and Amy Unruh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 *   See http://connectrapp.appspot.com/ for a demo, and links to more information 
 *   about this app and the book that it accompanies.
 */
package vns.client;

import java.util.ArrayList;
import java.util.List;

import vns.client.event.AccountEvent;
import vns.client.event.AccountEventHandler;
import vns.client.event.ObjectEditEvent;
import vns.client.event.ObjectEditEventHandler;
import vns.client.event.ObjectEvent;
import vns.client.event.ObjectEventHandler;
import vns.client.event.ObjectPropertyTypeEvent;
import vns.client.event.ObjectPropertyTypeEventHandler;
import vns.client.event.ObjectTypeEditEvent;
import vns.client.event.ObjectTypeEditEventHandler;
import vns.client.event.ObjectTypeEvent;
import vns.client.event.ObjectTypeEventHandler;
import vns.client.event.RoleEvent;
import vns.client.event.RoleEventHandler;
import vns.client.event.RuleSetEditEvent;
import vns.client.event.RuleSetEditEventHandler;
import vns.client.event.RuleSetEvent;
import vns.client.event.RuleSetEventHandler;
import vns.client.event.WelcomeEvent;
import vns.client.event.WelcomeEventHandler;
import vns.client.helper.Helper;
import vns.client.helper.RPCCall;
import vns.client.presenter.AccountPresenter;
import vns.client.presenter.CalendarVPanelPresenter;
import vns.client.presenter.ObjectDetailPresenter;
import vns.client.presenter.ObjectPresenter;
import vns.client.presenter.ObjectPropertyTypePresenter;
import vns.client.presenter.ObjectTypeDetailPresenter;
import vns.client.presenter.ObjectTypePresenter;
import vns.client.presenter.Presenter;
import vns.client.presenter.RolePresenter;
import vns.client.presenter.RuleSetDetailPresenter;
import vns.client.presenter.RuleSetPresenter;
import vns.client.presenter.SupperAdminPresenter;
import vns.client.service.AccountOAuthService;
import vns.client.service.AccountOAuthServiceAsync;
import vns.client.service.CalendarAllService;
import vns.client.service.CalendarAllServiceAsync;
import vns.client.service.ObjectPropertyService;
import vns.client.service.ObjectPropertyServiceAsync;
import vns.client.service.ObjectPropertyTypeService;
import vns.client.service.ObjectPropertyTypeServiceAsync;
import vns.client.service.ObjectService;
import vns.client.service.ObjectServiceAsync;
import vns.client.service.ObjectTypeService;
import vns.client.service.ObjectTypeServiceAsync;
import vns.client.service.RoleService;
import vns.client.service.RoleServiceAsync;
import vns.client.service.RuleSetService;
import vns.client.service.RuleSetServiceAsync;
import vns.client.service.SupperAdminService;
import vns.client.service.SupperAdminServiceAsync;
import vns.client.view.AccountUI;
import vns.client.view.CalendarVPanelUI;
import vns.client.view.ObjectDetailUI;
import vns.client.view.ObjectPropertyTypeUI;
import vns.client.view.ObjectTypeDetailUI;
import vns.client.view.ObjectTypeUI;
import vns.client.view.ObjectUI;
import vns.client.view.RoleUI;
import vns.client.view.RuleSetDetailUI;
import vns.client.view.RuleSetUI;
import vns.client.view.SupperAdminUI;
import vns.shared.AccountData;
import vns.shared.LoginInfo;
import vns.shared.ObjectDTO;
import vns.shared.ObjectPropertyDTO;
import vns.shared.ObjectTypeDTO;
import vns.shared.RuleSetDTO;
import vns.shared.SupperAdminDTO;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;

public class AppController implements ValueChangeHandler<String> {
	private final SimpleEventBus eventBus;
	private final ObjectPropertyTypeServiceAsync rpcOPType = GWT
			.create(ObjectPropertyTypeService.class);
	private final ObjectTypeServiceAsync rpcOType = GWT
			.create(ObjectTypeService.class);
	private final ObjectPropertyServiceAsync rpcOProperty = GWT
			.create(ObjectPropertyService.class);
	private final RoleServiceAsync rpcRole = GWT.create(RoleService.class);
	private final RuleSetServiceAsync rpcRuleSet = GWT
			.create(RuleSetService.class);
	private final ObjectServiceAsync rpcObject = GWT
			.create(ObjectService.class);
	private final CalendarAllServiceAsync rpcCalendar = GWT
			.create(CalendarAllService.class);
	private final AccountOAuthServiceAsync rpcAccount = GWT
			.create(AccountOAuthService.class);
	private final SupperAdminServiceAsync rpcSupperAdmin = GWT
			.create(SupperAdminService.class);

	private ObjectTypeDTO currentObjectTypeDTO;
	private ObjectDTO currentObjectDTO;
	private RuleSetDTO currentRuleSetDTO;
	private List<ObjectTypeDTO> listObjectTypeDTO = new ArrayList<ObjectTypeDTO>();
	private List<ObjectPropertyDTO> listObjectPropertyDTO = new ArrayList<ObjectPropertyDTO>();
	private String currrentOperation;
	private SupperAdminDTO adminDTO = null;
	private String lastToken = null;

	public AppController(SimpleEventBus eventBus) {
		this.eventBus = eventBus;
		bind();
	}

	private void bind() {
		History.addValueChangeHandler(this);

		// Welcome
		eventBus.addHandler(WelcomeEvent.TYPE, new WelcomeEventHandler() {

			@Override
			public void onWelcome(WelcomeEvent event) {
				doWelcome();
			}
		});

		// Account Login/LogOut
		eventBus.addHandler(AccountEvent.TYPE, new AccountEventHandler() {

			@Override
			public void onLogin(AccountEvent event) {

				doLogin(event.getOperation());

			}
		});

		// QL kieu thuoc tinh
		eventBus.addHandler(ObjectPropertyTypeEvent.TYPE,
				new ObjectPropertyTypeEventHandler() {

					@Override
					public void onLoad(ObjectPropertyTypeEvent event) {
						doLoadObjectPropertyTypeList();
					}
				});

		// QL kieu doi tuong
		eventBus.addHandler(ObjectTypeEvent.TYPE, new ObjectTypeEventHandler() {

			@Override
			public void onLoad(ObjectTypeEvent event) {
				doLoadObjectTypeList();
			}
		});

		// QL vai tro
		eventBus.addHandler(RoleEvent.TYPE, new RoleEventHandler() {

			@Override
			public void onLoad(RoleEvent event) {
				doLoadRoleList();
			}
		});

		// QL quy trinh
		eventBus.addHandler(RuleSetEvent.TYPE, new RuleSetEventHandler() {

			@Override
			public void onLoad(RuleSetEvent event) {
				doLoadRuleSetList();
			}
		});

		// Edit Object Type
		eventBus.addHandler(ObjectTypeEditEvent.TYPE,
				new ObjectTypeEditEventHandler() {

					@Override
					public void onEditObjectType(ObjectTypeEditEvent event) {
						doEditObjectType(event.getObjectTypeDTO());
					}
				});

		// Quan ly Object
		eventBus.addHandler(ObjectEvent.TYPE, new ObjectEventHandler() {

			@Override
			public void onLoad(ObjectEvent event) {
				doLoadObjectList(event.getObjectTypeDTO());
			}
		});

		// Edit Object
		eventBus.addHandler(ObjectEditEvent.TYPE, new ObjectEditEventHandler() {

			@Override
			public void onEditObject(ObjectEditEvent event) {
				doEditObject(event.getObjectDTO(), event.getObjectTypeDTO(),
						event.getListObjectPropertyDTO(), event.getOperation());
			}
		});
		
		// Edit Rule
		eventBus.addHandler(RuleSetEditEvent.TYPE, new RuleSetEditEventHandler() {
			
			@Override
			public void onLoad(RuleSetEditEvent event) {
				doEditRuleSet(event.getRuleSetDTO());
			}
		});

	}


	/**********************************************************************/

	protected void doWelcome() {
		if (adminDTO != null && "".equals(History.getToken())) {
			History.newItem("welcome");
		} else {
			History.fireCurrentHistoryState();
		}
	}

	private void doLoadSupperAdmin() {
		History.newItem("admin");
	}

	protected void doLogin(String operation) {
		if (operation.equalsIgnoreCase("adminlogin")) {
			History.newItem("adminlogin");
		} else
			History.newItem("login");
	}

	private void doLoadObjectPropertyTypeList() {
		History.newItem("optypeList");
	}

	private void doLoadObjectTypeList() {
		History.newItem("otypeList");
	}

	private void doLoadRuleSetList() {
		History.newItem("ruleSetList");
	}

	private void doLoadRoleList() {
		History.newItem("roleList");
	}

	private void doEditObjectType(ObjectTypeDTO o) {
		History.newItem("otypeEdit=" + o.getName());
		currentObjectTypeDTO = o;
		VNSmartUI.get().setLabelChildBreadcrum(
				"Chá»‰nh sá»­a kiá»ƒu Ä‘á»‘i tÆ°á»£ng: "
						+ currentObjectTypeDTO.getName());
		Presenter presenter = null;
		presenter = new ObjectTypeDetailPresenter(new ObjectTypeDetailUI(),
				eventBus, rpcOProperty, currentObjectTypeDTO);
		presenter.go(VNSmartUI.get().getChildPanel());
	}

	private void doEditObject(ObjectDTO o, ObjectTypeDTO ot,
			List<ObjectPropertyDTO> list, String operation) {
		currentObjectDTO = o;
		currentObjectTypeDTO = ot;
		listObjectPropertyDTO = list;
		currrentOperation = operation;
		
		lastToken = History.getToken();

		if (operation.equals("EDIT")) {
			History.newItem("objectEdit");
		} else {
			History.newItem("objectCreate");
		}
	}

	private void doLoadObjectList(ObjectTypeDTO ot) {
		currentObjectTypeDTO = ot;
		History.newItem("objectList=" + ot.getName());
	}

	protected void doEditRuleSet(RuleSetDTO ruleSetDTO) {
		lastToken = History.getToken();
		currentRuleSetDTO = ruleSetDTO;
		History.newItem("ruleEdit="+ruleSetDTO.getName());
		
	}
	/**********************************************************************/

	public void callLastToken(){
		History.newItem(lastToken);
	}
	
	public void setToken(String historyToken) {
		History.newItem(historyToken);
	}

	public void back() {
		History.back();
	}

	public void forward() {
		History.forward();
	}

	public void go() {
		loadVpanelList();
		loadSuperAdmin();

	}

	private void loadSuperAdmin() {
		new RPCCall<ArrayList<SupperAdminDTO>>() {

			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(ArrayList<SupperAdminDTO> result) {
				if (result.size() == 0) {
					doLoadSupperAdmin();
				} else {
					setAdminDTO(result.get(0));
					doWelcome();
				}
			}

			@Override
			protected void callService(
					AsyncCallback<ArrayList<SupperAdminDTO>> cb) {
				rpcSupperAdmin.Loadall(cb);
			}
		}.retry(3);
	}

	public void loadVpanelList() {
		new RPCCall<ArrayList<ObjectTypeDTO>>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Không load được kiểu danh sách!");
			}

			@Override
			public void onSuccess(ArrayList<ObjectTypeDTO> result) {
				final List<ObjectTypeDTO> listTemp = result;
				VNSmartUI.get().getVpanelList().clear();
				VNSmartUI.get().getVpanelPickList().clear();
				listObjectTypeDTO.clear();

				for (final ObjectTypeDTO o : listTemp) {
					Button bt = new Button();
					bt.setWidth("100%");
					bt.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							eventBus.fireEvent(new ObjectEvent(o));
						}
					});
					if (o.getPicklist()) {
						bt.setText("Danh sách: " + o.getName());
						VNSmartUI.get().getVpanelPickList().add(bt);
					} else {
						bt.setText("Quản lý: " + o.getName());
						VNSmartUI.get().getVpanelList().add(bt);
					}
					listObjectTypeDTO.add(o);
				}
			}

			@Override
			protected void callService(
					AsyncCallback<ArrayList<ObjectTypeDTO>> cb) {
				rpcOType.Loadall(cb);
			}
		}.retry(3);

	}

	public void loadVPanelPicklist() {
		CalendarVPanelPresenter pre = new CalendarVPanelPresenter(
				new CalendarVPanelUI(), eventBus, rpcCalendar);
		pre.go(VNSmartUI.get().getVpanelPickList());
	}

	/**********************************************************************/

	public void onValueChange(ValueChangeEvent<String> event) {
		String token = event.getValue();
		String param = null;
		String[] arg = token.split("=");
		token = arg[0];
		if (token != null) {

			VNSmartUI.get().getChildPanel().clear();
			VNSmartUI.get().getLabelChildBreadcrum().setText("");

			Presenter presenter = null;
			if (token.equals("welcome")) {
				if (VNSmartUI.get().getAccountData() == null) {
					presenter = new AccountPresenter(new AccountUI(), eventBus,
							rpcAccount, adminDTO);
					VNSmartUI.get().getDialogBox().setText("Tài khoản: ");
					presenter.go(VNSmartUI.get().getDialogBox());
				}
			}
			if (token.equals("adminlogin")) {
				presenter = new SupperAdminPresenter(new SupperAdminUI(),
						eventBus, rpcSupperAdmin, adminDTO, "login");
				presenter.go(VNSmartUI.get().getDialogBox());
			}
			if (token.equals("admin")) {
				presenter = new SupperAdminPresenter(new SupperAdminUI(),
						eventBus, rpcSupperAdmin, adminDTO, "edit");
				presenter.go(VNSmartUI.get().getDialogBox());
			}
			if (token.equals("login")) {
				if (VNSmartUI.get().getDialogBox().isShowing()) {
					VNSmartUI.get().getDialogBox().hide();
				}
				VNSmartUI.get().signIn();
				String href = VNSmartUI.get().getAccountData()
						.getGoogleLogoutUrl();
				VNSmartUI.get().setHtmlAccount(
						"Xin Chào <b>"
								+ VNSmartUI.get().getAccountData()
										.getGoogleNick() + "</b> | <a href='"
								+ href + "'> Đăng xuất </a>");
				// loadVPanelOperation();
			}
			if (token.equals("logout")) {
				VNSmartUI.get().signOut();
			}
			if (token.equals("optypeList")) {
				VNSmartUI.get().setLabelBreadcrum("Kiểu Thuộc Tính");
				presenter = new ObjectPropertyTypePresenter(
						new ObjectPropertyTypeUI(), eventBus, rpcOPType);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("otypeList")) {
				VNSmartUI.get().setLabelBreadcrum("Danh sách");
				presenter = new ObjectTypePresenter(new ObjectTypeUI(),
						eventBus, rpcOType);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("roleList")) {
				VNSmartUI.get().setLabelBreadcrum("Vai trò và quyền hạn");
				presenter = new RolePresenter(new RoleUI(), eventBus, rpcRole);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("ruleSetList")) {
				VNSmartUI.get().setLabelBreadcrum("Quy trình, ràng buộc");
				presenter = new RuleSetPresenter(new RuleSetUI(), eventBus,
						rpcRuleSet, rpcOType);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("objectList")) {
				VNSmartUI.get().setLabelBreadcrum(
						"Danh sách: " + currentObjectTypeDTO.getName());
				presenter = new ObjectPresenter(new ObjectUI(), eventBus,
						rpcObject, currentObjectTypeDTO);
				presenter.go(VNSmartUI.get().getMainPanel());
			}
			if (token.equals("objectEdit")) {
				VNSmartUI.get().setLabelBreadcrum(
						"Cập nhật: " + currentObjectDTO.getMain());
				presenter = new ObjectDetailPresenter(new ObjectDetailUI(),
						eventBus, currentObjectDTO, currentObjectTypeDTO,
						listObjectPropertyDTO, rpcObject, currrentOperation);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("objectCreate")) {
				VNSmartUI.get().setLabelBreadcrum(
						"Tạo mới: " + currentObjectTypeDTO.getName());
				presenter = new ObjectDetailPresenter(new ObjectDetailUI(),
						eventBus, currentObjectDTO, currentObjectTypeDTO,
						listObjectPropertyDTO, rpcObject, currrentOperation);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}
			if (token.equals("ruleEdit")) {
				VNSmartUI.get().setLabelBreadcrum(
						"Thiết lập quy trình: " + currentRuleSetDTO.getName());
				presenter = new RuleSetDetailPresenter(new RuleSetDetailUI(), eventBus, rpcRuleSet);
				presenter.go(VNSmartUI.get().getMainPanel());
				return;
			}

		}
	}

	public void setAdminDTO(SupperAdminDTO adminDTO) {
		this.adminDTO = adminDTO;
	}

	public SupperAdminDTO getAdminDTO() {
		return adminDTO;
	}
}
